package com.person.jiaiplan.util;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.excel.util.MapUtils;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.alibaba.excel.write.metadata.fill.FillWrapper;
import com.person.jiaiplan.contant.ConstGroupConstant;
import com.person.jiaiplan.pojo.R;
import com.person.jiaiplan.pojo.dto.summary.*;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Author wend
 * Excel 工具类
 */
public class ExcelUtils<T> {


    private static final String templateFileDir = System.getProperty("user.dir") + File.separator + "src\\main\\resources" + File.separator + "excelTemplate" + File.separator;
    /**
     * 导出对象
     */
    private List<T> excelData;
    /**
     * web响应
     */
    private HttpServletResponse response;
    /**
     * 数据类型的class
     */
    private Object dataClass;
    /**
     * 自定义表头
     */
    private Set<String> customHeaders;


    public ExcelUtils(HttpServletResponse response) {
        this.response = response;
    }

    public ExcelUtils(List<T> excelData, HttpServletResponse response, Object dataClass) {
        this.excelData = excelData;
        this.response = response;
        this.dataClass = dataClass;
    }


    /**
     * 带有自定义表头的 构造器
     *
     * @param excelData
     * @param response
     * @param dataClass
     * @param customHeaders
     */
    public ExcelUtils(List<T> excelData, HttpServletResponse response, Object dataClass, Set<String> customHeaders) {
        this.excelData = excelData;
        this.response = response;
        this.dataClass = dataClass;
        this.customHeaders = customHeaders;
    }

    /**
     * 处理导出Excel 的 response
     */
    public static void handleExcelResponse(String excelName, HttpServletResponse response) throws Exception {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode(excelName, "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
    }

    /**
     * 重置响应对象
     *
     * @param response
     */
    public static void responseReset(HttpServletResponse response) {
        response.reset();
        response.setContentType("application/json");
        response.setCharacterEncoding("utf-8");
    }

    /**
     * 增加新表头（同一行)
     *
     * @param list
     * @param headerName
     * @return
     */
    public static void addNewHeader(List<List<String>> list, String headerName) {
        List<String> head = ListUtils.newArrayList();
        head.add(headerName);
        list.add(head);
    }

    /**
     * 使用 easyExcel 导出到 web
     *
     * @return
     */
    public R writeToWebByEasyExcel(String excelName, String sheetName) {
        // todo 关于 easy excel 表头字段支持多语言，需要用反射动态修改实现 (但是这个不着急)
        try {
            handleExcelResponse(excelName, response);

            // 包含自定义表头的实现
            if (customHeaders != null) {
                EasyExcel.write(response.getOutputStream(), (Class) dataClass).autoCloseStream(Boolean.FALSE).includeColumnFiledNames(customHeaders).sheet(sheetName)
                        .doWrite(excelData);
            } else {
                // 这里需要设置不关闭流
                EasyExcel.write(response.getOutputStream(), (Class) dataClass).autoCloseStream(Boolean.FALSE).sheet(
                                sheetName)
                        .doWrite(excelData);
            }

        } catch (Exception e) {
            e.printStackTrace();
            responseReset(response);
            return R.failed("excel导出失败");
        }
        return null;
    }

    /**
     * easyExcel ：通用的自定义 Excel 导出方法
     * 也可以当成一个模板使用
     *
     * @param head
     * @param dataList
     * @return
     */
    public R writeToWebByCustomHeaderAndDataList(List<List<String>> head, List<List<Object>> dataList, String sheetName) {

        try {
            // 这里需要设置不关闭流
            EasyExcel.write(response.getOutputStream()).autoCloseStream(Boolean.FALSE).
                    sheet(sheetName).head(head)
                    .doWrite(dataList);
        } catch (Exception e) {
            e.printStackTrace();
            responseReset(response);
            return R.failed("excel导出失败");
        }
        return null;
    }

    /**
     * 写周总结Excel
     *
     * @param excelData
     * @param response
     * @return
     * @throws Exception
     */
    public R weeklySummaryTableFill(WeeklySummaryReqDTO reqDTO, List<WeeklySummaryResDTO> excelData, HttpServletResponse response) {
        String templateFileName =
                templateFileDir + "weeklySummaryTemplate.xlsx";

        String fileName = "周总结";
        // 这个sheetName必须和模板中的sheet一致
        String sheetName = "本周总结";

        try {
            ExcelUtils.handleExcelResponse(fileName, response);

            // 这里需要设置不关闭流

            FillConfig fillConfig = FillConfig.builder().forceNewRow(true).build();
            List<WeeklySummaryResDTO> finishList = excelData.stream().filter(e -> e.getPlanStatus().equals(2)).collect(Collectors.toList());
            List<WeeklySummaryResDTO> runningList = excelData.stream().filter(e -> e.getPlanStatus().equals(1)).collect(Collectors.toList());

            ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).withTemplate(templateFileName).autoCloseStream(Boolean.FALSE).build();
            Map<String, Object> map = MapUtils.newHashMap();
            map.put("queryStartTime", reqDTO.getStartTime());
            map.put("queryEndTime", reqDTO.getEndTime());
            map.put("operatorTypeStr", ConstGroupConstant.getConstGroupValue("constgroup_operator_type", Integer.valueOf(reqDTO.getOperatorType())));

            WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).build();
            excelWriter.fill(map, writeSheet);
            excelWriter.fill(new FillWrapper("data1", finishList), fillConfig, writeSheet);
            excelWriter.fill(new FillWrapper("data2", runningList), fillConfig, writeSheet);
            excelWriter.finish();

        } catch (Exception e) {
            e.printStackTrace();
            ExcelUtils.responseReset(response);
            return R.failed("excel导出失败");
        }
        return null;
    }

    /**
     * 填充年度总结Excel
     *
     * @param reqDTO
     * @param excelData
     * @param response
     * @return
     */
    public R annualSummaryTableFill(AnnualSummaryReqDTO reqDTO, List<AnnualSummaryResDTO> excelData, AnnualSummaryCountResDTO annualSummaryCountResDTO, HttpServletResponse response) {
        String templateFileName =
                templateFileDir + "annualSummaryTemplate.xlsx";

        String fileName = "年度总结";
        // 这个sheetName必须和模板中的sheet一致
        String sheetName = "年度总结";

        try {
            ExcelUtils.handleExcelResponse(fileName, response);

            // 每写数据要创建一个新行

            FillConfig fillConfig = FillConfig.builder().forceNewRow(true).build();


            ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).withTemplate(templateFileName).autoCloseStream(Boolean.FALSE).build();
            Map<String, Object> map = MapUtils.newHashMap();
            map.put("queryStartTime", reqDTO.getStartTime());
            map.put("queryEndTime", reqDTO.getEndTime());
            map.put("operatorTypeStr", ConstGroupConstant.getConstGroupValue("constgroup_operator_type", Integer.valueOf(reqDTO.getOperatorType())));

            WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).build();
            excelWriter.fill(map, writeSheet);
            excelWriter.fill(new FillWrapper("data1", excelData), fillConfig, writeSheet);
            excelWriter.fill(new FillWrapper("data2", Collections.singleton(annualSummaryCountResDTO)), fillConfig, writeSheet);
            excelWriter.finish();

        } catch (Exception e) {
            e.printStackTrace();
            ExcelUtils.responseReset(response);
            return R.failed("excel导出失败");
        }
        return null;
    }


}
